/*
 * Copyright (C) 2008
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.sca4idea.references;

import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlFile;
import com.googlecode.sca4idea.util.ComponentResolver;
import com.googlecode.sca4idea.psi.SCAComponentTagPsiElement;
import com.googlecode.sca4idea.providers.SCAProvider;
import com.googlecode.sca4idea.facet.SCAFacet;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * ReferenceProvider for resolving target values.
 *
 * @author paul.jones
 */
public class PromotedReferenceReferenceProvider extends AbstractReferenceProvider {
    @NotNull
    public PsiReference[] getReferencesByString(String s, PsiElement psiElement, int i) {
        final SCAProvider provider = SCAFacet.getProviderForElement(psiElement);
        List<PsiReference> result = new ArrayList<PsiReference>();
        for (TextRange range : SCAReferencesUtil.splitRanges(s)) {
            // Split the range into the before and after slash parts
            final TextRange[] parts = ComponentResolver.splitSlashedReference(s, range);

            result.add(
              new XmlAttributeValuePsiReference((XmlAttributeValue)psiElement, parts[0]) {
                    public boolean isSoft() {
                        return PromotedReferenceReferenceProvider.this.isSoft();
                    }

                    public Object[] getVariants() {
                        PsiFile psiFile = getElement().getContainingFile();
                        List<Object> result = new ArrayList<Object>();
                        for (SCAComponentTagPsiElement el : ComponentResolver.getComponents(provider, (XmlFile)psiFile).values()) {
                            result.addAll(Arrays.asList(el.getVariantsOfReferences(true)));
                        }
                        return result.toArray();
                    }

                    public PsiElement resolve() {
                        String componentName = ComponentResolver.getTargetComponentName(getCanonicalText());
                        if(StringUtil.isNotEmpty(componentName)) {
                            PsiFile psiFile = getElement().getContainingFile();
                            Map<String, SCAComponentTagPsiElement> components = ComponentResolver.getComponents(provider, (XmlFile)psiFile);
                            return components.get(componentName);
                        }
                        return null;
                    }
              });

            if (parts.length == 2) {
                result.add(
                      new XmlAttributeValuePsiReference((XmlAttributeValue)psiElement, parts[1]) {
                            public boolean isSoft() {
                                return PromotedReferenceReferenceProvider.this.isSoft();
                            }

                            public Object[] getVariants() {
                                PsiFile psiFile = getElement().getContainingFile();
                                List<Object> result = new ArrayList<Object>();
                                for (SCAComponentTagPsiElement el : ComponentResolver.getComponents(provider, (XmlFile)psiFile).values()) {
                                    result.addAll(Arrays.asList(el.getVariantsOfReferences(true)));
                                }
                                return result.toArray();
                            }

                            public PsiElement resolve() {
                                String componentName = getTextFromRange(parts[0]);
                                String referenceName = getCanonicalText();
                                if(StringUtil.isNotEmpty(componentName)) {
                                    PsiFile psiFile = getElement().getContainingFile();
                                    Map<String, SCAComponentTagPsiElement> components = ComponentResolver.getComponents(provider, (XmlFile)psiFile);
                                    SCAComponentTagPsiElement component = components.get(componentName);
                                    if (component == null) {
                                        return null;
                                    }

                                    if (referenceName != null) {
                                        return component.resolveReference(referenceName);
                                    }

                                    return component;
                                }
                                return null;
                            }
                      });
            }
        }

        return result.toArray(new PsiReference[result.size()]);
    }

}